package org.galagosearch.core.tools;

import java.io.FileWriter;
import java.io.PrintStream;
import java.util.ArrayList;

import org.galagosearch.core.index.IndexWriter;
import org.galagosearch.core.index.PositionIndexReader;
import org.galagosearch.core.index.VersionedPositionIndexReader;
import org.galagosearch.core.index.VersionedPostingList;
import org.galagosearch.core.retrieval.Retrieval;
import org.galagosearch.core.retrieval.structured.IndexIterator;
import org.galagosearch.core.store.DocumentStore;
import org.galagosearch.core.store.SnippetGenerator;

public class TemporalCoalescing {
	Retrieval retrieval;
	IndexIterator iterator;
	PrintStream output;
	String timeEnd,timeBegin,identifier,tcIndex;
	int revID;
	double e;
	IndexWriter iw;
	FileWriter fw;
	String lastTerm="";
	int numberOfEntries=0;
	ArrayList<String> termList=new ArrayList<String>();
    ArrayList<Integer> tfList=new ArrayList<Integer>();
    ArrayList<Integer> docIDList=new ArrayList<Integer>();
    ArrayList<String> timeBeginList=new ArrayList<String>();
    ArrayList<String> timeEndList=new ArrayList<String>();
    ArrayList<String> identifierList=new ArrayList<String>();
    
	public TemporalCoalescing(Retrieval retrieval,IndexIterator iterator,PrintStream output,String tcIndex) {
        this.retrieval = retrieval;
        this.iterator=iterator;
        this.output=output;
        this.e=0.00;
        this.tcIndex=tcIndex;
        
        try{
       // fetchData();
        	/*iw=new IndexWriter(tcIndex);
        	iw.getManifest().add("writerClass", getClass().getName());
            iw.getManifest().add("readerClass", VersionedPositionIndexReader.class.getName());*/
        	fw=new FileWriter(tcIndex) ;
        }catch(Exception e){e.printStackTrace();}
    }
	private void writeToIndex(TimedDataElement[] tde, String term, int docID) throws Exception
	{
		if(lastTerm.compareTo("")==0 || lastTerm.compareTo(term)!=0)
		{
			fw.write("\n");
			fw.write(term);	
		}
		for(TimedDataElement t: tde)
		{
			fw.write(":["+docID+","+t.tf+","+t.tb+","+t.te+"]");
			numberOfEntries++;
		}
		lastTerm=term;
	}
	
	private void fetchData() throws Exception
	{
		do {
            String termDocPosting=iterator.getRecordString();
            output.println(termDocPosting);
            
            int termPos=termDocPosting.indexOf(',');
            String term=termDocPosting.substring(0,termPos);
            termDocPosting=termDocPosting.substring(termPos+1);
            termPos=termDocPosting.indexOf(',');
            int docID=Integer.parseInt(termDocPosting.substring(0,termPos));
            termDocPosting=termDocPosting.substring(termPos+1);
            int tf=getTFFromPosting(termDocPosting);
            
        	getInfo(docID);
        	//System.out.println(term+"\t"+docID+"\t"+tf+"\t"+identifier+"\t"+timeBegin);
        	
        	termList.add(term);
        	tfList.add(tf);
        	docIDList.add(docID);
        	timeBeginList.add(timeBegin);
        	timeEndList.add(timeEnd);
        	identifierList.add(identifier);
        } while (iterator.nextRecord());
		
	}
	private int getTFFromPosting(String termDocPosting) {
		// TODO Auto-generated method stub
		int count=0;
		int len=termDocPosting.length();
		char[] temp=termDocPosting.toCharArray();
		for(int i=0;i<len;i++)
		{
			if(temp[i]==',') count++; 
		}
		return count+1;
	}
	public void getInfo(int document) throws Exception
	{
		 identifier = retrieval.getDocumentName(document);
	    int tempPos=identifier.lastIndexOf('+');
	    revID=Integer.parseInt(identifier.substring(tempPos+1));
	    identifier=identifier.substring(0, tempPos);
	    tempPos=identifier.lastIndexOf('+');
	    timeEnd=identifier.substring(tempPos+1);
	    identifier=identifier.substring(0, tempPos);
	    tempPos=identifier.lastIndexOf('+');
	    timeBegin=identifier.substring(tempPos+1);
	    identifier=identifier.substring(0,tempPos);
	} 
	public void process() throws Exception
	{
		String termDocPosting=iterator.getRecordString();
		TimedDataElement[] tde;
		iterator.nextRecord();
        output.println(termDocPosting);
        
        int termPos=termDocPosting.indexOf(',');
        String pTerm=termDocPosting.substring(0,termPos);
        termDocPosting=termDocPosting.substring(termPos+1);
        termPos=termDocPosting.indexOf(',');
        int pDocID=Integer.parseInt(termDocPosting.substring(0,termPos));
        termDocPosting=termDocPosting.substring(termPos+1);
        int pTF=getTFFromPosting(termDocPosting);
    	getInfo(pDocID);
        String pIdentifier=identifier;

        termList.add(pTerm);
    	tfList.add(pTF);
    	docIDList.add(pDocID);
    	timeBeginList.add(timeBegin);
    	timeEndList.add(timeEnd);
    	identifierList.add(identifier);
    	//System.out.println(pTerm+"\t"+pDocID+"\t"+pTF+"\t"+identifier+"\t"+timeBegin);
		do {
             termDocPosting=iterator.getRecordString();
            output.println(termDocPosting);
            
            termPos=termDocPosting.indexOf(',');
            String term=termDocPosting.substring(0,termPos);
            termDocPosting=termDocPosting.substring(termPos+1);
            termPos=termDocPosting.indexOf(',');
            int docID=Integer.parseInt(termDocPosting.substring(0,termPos));
            termDocPosting=termDocPosting.substring(termPos+1);
            int tf=getTFFromPosting(termDocPosting);
            
        	getInfo(docID);
        	
        	
        	
        	if(term.compareTo(pTerm)!=0)
        	{
        		
        		//System.out.println("Term list Size: "+termList.size());
        		if(term.compareTo("council")==0)
        		{
        			//jst break here;
        			int i=1;
        		}
        		tde= performTC(termList,tfList,docIDList,timeBeginList,timeEndList,identifierList);
        		writeToIndex(tde, termList.get(0), docIDList.get(0));
        		/*if(vpl!=null) 
        		{
        			vpl.close();
        			iw.add(vpl);
        		}
        		vpl=null;*/
        		
        		termList.clear();
        		tfList.clear();
        		docIDList.clear();
        		timeBeginList.clear();
        		timeEndList.clear();
        		identifierList.clear();
        		//System.out.println("=======Start");
        		pTerm=term;
        	}
        	else if(pIdentifier.compareTo(identifier)!=0)
        	{
        		//System.out.println("\nTerm List Size: "+termList.size()+"");
        		tde=performTC(termList,tfList,docIDList,timeBeginList,timeEndList,identifierList);
        		writeToIndex(tde, termList.get(0), docIDList.get(0));
        	/*	if(vpl!=null) 
        		{
        			vpl.close();
        			iw.add(vpl);
        		} 
        		vpl=null;*/
        		
        		termList.clear();
        		tfList.clear();
        		docIDList.clear();
        		timeBeginList.clear();
        		timeEndList.clear();
        		identifierList.clear();
        	
        	}
        	
        	termList.add(term);
        	tfList.add(tf);
        	docIDList.add(docID);
        	timeBeginList.add(timeBegin);
        	timeEndList.add(timeEnd);
        	identifierList.add(identifier);
        	
        	pIdentifier=identifier;
        	//System.out.println(term+"\t"+docID+"\t"+tf+"\t"+identifier+"\t"+timeBegin);

        	
        	/*termList.add(term);
        	tfList.add(tf);
        	docIDList.add(docID);
        	timeBeginList.add(timeBegin);
        	timeEndList.add(timeEnd);
        	identifierList.add(identifier);*/
        } while (iterator.nextRecord());
	//	iw.close();
		fw.close();
		System.out.println("Total "+numberOfEntries+ " entries");
	
	}
	private TimedDataElement[] performTC(ArrayList<String> termList2,
			ArrayList<Integer> tfList2, ArrayList<Integer> docIDList2,
			ArrayList<String> timeBeginList2, ArrayList<String> timeEndList2,
			ArrayList<String> identifierList2) throws Exception{
		// TODO Auto-generated method stub
		//actually all ther entries in the termList2 will be same. And so is the case with identifierList2.
		ArrayList<String> opTermList2=new ArrayList<String>();
		ArrayList<Integer> opTFList2= new ArrayList<Integer>(); 
		ArrayList<Integer> opDocIDList2=new ArrayList<Integer>();
		ArrayList<String> opTimeBeginList2=new ArrayList<String>(); 
		ArrayList<String> opTimeEndList2=new ArrayList<String>();
		//ArrayList<String> identifierList2
		String term=termList2.get(0);
		int baseDocID=docIDList2.get(0);
		
		int p_min=tfList2.get(0);
		int p_max=tfList2.get(0);
		int p=tfList2.get(0);
		String tb=timeBeginList2.get(0);
		String te=timeEndList2.get(0);
		
		int len=tfList2.size();
		
		for(int i=1;i<len;i++)
		{
			int p_min_new=(p_min<tfList2.get(i))?p_min:tfList2.get(i);
			int p_max_new=(p_max>tfList2.get(i))?p_max:tfList2.get(i);
			double p_new=optrep(p_min_new,p_max_new);
			
			if(err(p_min,p_new)<=e && err(p_max,p_new)<=e)
			{
				p_min=p_min_new;
				p_max=p_max_new;
				p=(int)p_new;
				te=timeEndList2.get(i);
			}
			else
			{
				opTFList2.add(p);
				opTermList2.add(term);
				opTimeBeginList2.add(tb);
				opTimeEndList2.add(te);
				opDocIDList2.add(baseDocID);
				
				p_min=tfList2.get(i);
				p_max=tfList2.get(i);
				p=tfList2.get(i);
				tb=timeBeginList2.get(i);
				te=timeEndList2.get(i);	
			}
		}
		opTFList2.add(p);
		opTermList2.add(term);
		opTimeBeginList2.add(tb);
		opTimeEndList2.add(te);
		opDocIDList2.add(baseDocID);
		
		/*VersionedPostingList vpl=new VersionedPostingList();
		vpl.setWord(term.getBytes());
		vpl.addDocument(baseDocID);

		for(int i=0;i<opTFList2.size();i++)
		{	
			vpl.addTF(opTFList2.get(i));
			vpl.addTB(timeString2IntString(opTimeBeginList2.get(i)));
			vpl.addTE(timeString2IntString(opTimeBeginList2.get(i)));
		}*/
		TimedDataElement[] tde=new TimedDataElement[opTFList2.size()];
		for(int i=0;i<tde.length;i++)
		{
			tde[i]=new TimedDataElement(opTFList2.get(i),timeString2IntString(opTimeBeginList2.get(i)),timeString2IntString(opTimeEndList2.get(i)));
		}
		//return vpl;
		return tde;
		
	}
	private double err(double p_min, double p_new) {
		// TODO Auto-generated method stub
		return Math.abs(p_min-p_new)/Math.abs(p_min);
	}
	private double optrep(int p_min_new, int p_max_new) {
		// TODO Auto-generated method stub
		return (Math.ceil((2.0*p_max_new*p_min_new)/(p_max_new+p_min_new)));
	}
	 private int timeString2IntString(String a)
	 {
    	//System.out.println("fromInsideOfMethod:\t"+a);
    	if(a.compareTo("-1")==0) return -1;
    	return Integer.parseInt(a.substring(2,4)+a.substring(5,7)+a.substring(8,10)+a.substring(11,13)+a.substring(14,16));
    
    }
	 class TimedDataElement
	 {
		 int tf;
		 int tb;
		 int te;
		 public TimedDataElement(int tf,int tb, int te){ this.tf=tf; this.tb=tb; this.te=te;}
	 }
	 
}
